home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
prolog
/
brklyprl.lha
/
Emulator
/
fast_copy.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-14
|
9KB
|
330 lines
/* Copyright (C) 1988, 1989 Herve' Touati, Aquarius Project, UC Berkeley */
/* Copyright Herve' Touati, Aquarius Project, UC Berkeley */
#ifdef WITH_GC
#include <stream.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "tags.h"
#include "instr.h"
#include "hash_table.h"
#include "string_table.h"
#include "scan.h"
#include "inst_args.h"
#include "inst_table.h"
#include "memory.h"
#include "basics.h"
#include "top_level.h"
#include "gc.h"
#include "mark_copy.h"
/* LOCAL DECLARATIONS */
static DownStack FAST_MARK_STACK;
static CopyStack FAST_COPY_STACK;
/* if does not point directly to new space, either it dereferences to */
/* a pointer to new space that belongs to some living environment, */
/* that will be traced later on, or to some old environment, which */
/* modification would then have been trailed. Therefore, there is no */
/* need to dereference */
void Env::fast_copy()
{
#ifdef WITH_VIRTUAL_BACK
Cell* y = e + Y1_ENV_OFFSET + already_treated;
Cell* y0 = e + Y1_ENV_OFFSET + size;
for (; y < y0; y++) {
Cell* ptr = y;
Cell val = *ptr;
while (get_tag(val) == TAGREF && addr(val) >= E0 && addr(val) != ptr) {
ptr = addr(val);
val = *ptr;
}
if (get_tag(val) == TAGCONST) continue;
if (to_new_space(addr(val)))
copy_from_base(ptr);
}
#else
Cell* y = e + Y1_ENV_OFFSET + already_treated;
Cell* y0 = e + Y1_ENV_OFFSET + size;
for (; y < y0; y++) {
if (get_tag(*y) == TAGCONST) continue;
if (to_new_space(addr(*y)))
copy_from_base(y);
}
#endif
}
/* Needs to make sure that no unbound variable is left in registers */
void fast_copy_restore_top_env()
{
Cell* PreviousE = cellp(E[E_ENV_OFFSET]);
int arity = instrp(E[P_ENV_OFFSET])->arg2;
E = PreviousE;
for (int i = 0; i < arity; i++) {
X[i] = deref(E[Y1_ENV_OFFSET + i]);
if (X[i] == make_ptr(TAGREF, &E[Y1_ENV_OFFSET + i])) {
Cell new_var = make_ptr(TAGREF, FAST_COPY_STACK.top());
FAST_COPY_STACK.push(new_var);
X[i] = E[Y1_ENV_OFFSET + i] = new_var;
}
}
}
/* CHOICE POINTS */
void setup_cps_fast_copy()
{
/* treat the case of the cps such that B.h == HMIN now */
Cell* b = B2 = B;
while (cellp(b[H_CP_OFFSET]) == HMIN) {
b[H_CP_OFFSET] = cell(H2);
b += FIXED_CP_SIZE + b[SIZE_CP_OFFSET];
}
/* creates a topmost choice point */
B -= FIXED_CP_SIZE;
B[E_CP_OFFSET] = cell(E);
B[H_CP_OFFSET] = cell(H);
B[TR_CP_OFFSET] = cell(TR);
B[P_CP_OFFSET] = 0; /* unused */
B[SIZE_CP_OFFSET] = 0;
/* set B2 to be above E2, TR2 as well; save previous contents */
SAVED_CP.tr = cellp(B2[TR_CP_OFFSET]);
SAVED_CP.e = cellp(B2[E_CP_OFFSET]);
SAVED_CP.h = cellp(B2[H_CP_OFFSET]);
TR2 = min(TR2, SAVED_CP.tr);
E2 = max(E2, SAVED_CP.e);
B2[TR_CP_OFFSET] = cell(TR2);
B2[E_CP_OFFSET] = cell(E2);
B2[H_CP_OFFSET] = cell(HMIN);
}
void restore_cps_fast_copy()
{
/* restore B2 to its initial contents */
B2[TR_CP_OFFSET] = cell(SAVED_CP.tr);
B2[E_CP_OFFSET] = cell(SAVED_CP.e);
B2[H_CP_OFFSET] = cell(SAVED_CP.h);
/* compute the new values of H, H2, TR, TR2, E2 */
H = HMIN;
H2 = FAST_COPY_STACK.top();
TR = TR2 = cellp(B[TR_CP_OFFSET]);
E2 = E;
/* remove the dummy topmost choice point */
B += FIXED_CP_SIZE;
}
/* takes advantage of the fact that the tag bit is in the lower bits */
void fast_copy_trail_1()
{
register Cell* tr0 = cellp(B[TR_CP_OFFSET]);
register Cell* tr = cellp(B2[TR_CP_OFFSET]);
register Cell* copy_tr = tr;
register Cell* h = cellp(B2[H_CP_OFFSET]);
register Cell* e = cellp(B2[E_CP_OFFSET]);
for (; tr > tr0; tr--) {
if (cellp(*tr) < h || (cellp(*tr) < e && cellp(*tr) >= E0))
*copy_tr-- = *tr;
}
B[TR_CP_OFFSET] = cell(copy_tr);
}
void fast_copy_trail_2()
{
register Cell* tr0 = cellp(B[TR_CP_OFFSET]);
register Cell* tr = cellp(B2[TR_CP_OFFSET]);
for (; tr > tr0; tr--) {
register Cell* ptr = addr(*tr);
if (ptr >= E2 || (ptr < E0 && ptr >= HMIN))
continue;
if (pointer_to_new(*ptr))
copy_from_base(ptr);
}
}
void fast_copy_trail()
{
fast_copy_trail_1();
fast_copy_trail_2();
}
/* control stacks */
/* we do the traversal of the environment stack and the choice point */
/* stack together. that way we can avoid having to traverse the */
/* records twice, and we do not have to use marking nor any extra */
/* space: just two extra structures. */
/* will be quite easy to add virtual backtracking inside this routine */
/* it works as follows: first visit all envs above the topmost choice */
/* point. then visit all envs that are above the next living env. two */
/* loops alternating, one visiting next living envs, one visiting the */
/* next preserved envs. if a given env is shared, its living part is */
/* first entirely marked, then we wait until the last choice point */
/* that preserved that env and mark the part that is preserved. */
void fast_copy_control()
{
/* only living objects in that case */
Env env(E);
for (;;) {
if (env.e <= E2) {
if (env.e == E2)
env.fast_copy();
break;
}
env.fast_copy();
env.next();
}
}
/* we save and later restore the topmost entry in the COPY_STACK at */
/* the time this routine is called. This is to simplify the algorithm */
/* and avoid copying many times. Here, the main difficulty is the */
/* correct treatment of refs. Since the order does not matter any */
/* more here, we can be even a bit more efficient. Each time we */
/* encounter a ref, we dereference it. If we get a constant, we just */
/* copy the constant into the origin. If we get an unbound variable, */
/* we rebind it backwards, and set the original pointer to unbound. */
/* This may create pointers from new to base space for a while, so we */
/* should be careful. The idea is to always dereference fully, no */
/* matter what, and look at where the result is. Only stop when */
/* marked. Using the FAST_MARK_STACK helps a lot, though it cannot be */
/* deeper than one element. */
void copy_from_base(Cell* p)
{
FAST_MARK_STACK.init(B);
FAST_MARK_STACK.push(p);
for (;;) {
Cell* var;
if (FAST_COPY_STACK.nonempty())
var = FAST_COPY_STACK.pop();
else if (FAST_MARK_STACK.nonempty())
var = FAST_MARK_STACK.pop();
else
break;
switch (get_tag(*var)) {
case TAGCONST:
break;
case TAGREF:
{
Cell* ptr = addr(*var);
if (ptr < HMIN || ptr >= E0) {
if (*var == *ptr) {
if (ptr > var)
*ptr = *var = make_ptr(TAGREF, var);
} else {
*var = *ptr;
FAST_MARK_STACK.push(var);
}
} else if (marked(ptr)) {
*var = make_ptr(TAGREF, reloc_addr(ptr));
} else if (*var == *ptr) {
*ptr = *var = make_ptr(TAGREF, var);
} else {
*var = *ptr;
FAST_MARK_STACK.push(var);
}
}
break;
case TAGLIST:
{
Cell* list = addr(*var);
if (list >= HMIN) {
if (marked(list)) {
*var = make_ptr(TAGLIST, reloc_addr(list));
} else {
*var = make_ptr(TAGLIST, FAST_COPY_STACK.top());
for (int i = 0; i < 2; i++) {
mark(list + i);
Cell* dest = FAST_COPY_STACK.top();
FAST_COPY_STACK.push(list[i]);
set_reloc_addr(list + i, dest);
}
}
}
}
break;
case TAGSTRUCT:
{
Cell* str = addr(*var);
if (str >= HMIN) {
if (marked(str)) {
*var = make_ptr(TAGSTRUCT, reloc_addr(str));
} else {
*var = make_ptr(TAGSTRUCT, FAST_COPY_STACK.top());
int i0 = get_int(str[1]) + 2;
for (int i = 0; i < i0; i++) {
mark(str + i);
Cell* dest = FAST_COPY_STACK.top();
FAST_COPY_STACK.push(str[i]);
set_reloc_addr(str + i, dest);
}
}
}
}
break;
}
}
}
/* Basic Initializations */
void fast_copy_gc_init()
{
#ifdef WITH_VIRTUAL_BACK
MARK = 2 * ((GC_COUNTER % 127) + 1); /* values from 2 to 254 */
#else
MARK = (GC_COUNTER % 255) + 1; /* values from 1 to 255 */
#endif
GC_COUNTER++;
FAST_COPY_STACK.init(H2);
}
/* Collect some data */
/* some basic data: mark(scan,recovered), copy(scan,recovered), cputime */
/* the data are given in number of cells, milliseconds. */
void fast_copy_stats()
{
gc_scanned += H_entry_value - HMIN;
gc_copy_scanned += H_entry_value - HMIN;
gc_survivors += H2 - H2_entry_value;
tr_scanned += TR2_entry_value - TR_entry_value;
tr_survivors += TR2_entry_value - TR;
if (DISPLAY_GC) {
cout << "gc(";
display_stat1("copy", H_entry_value - HMIN, H2 - H2_entry_value);
display_stat1("tr", TR2_entry_value-TR_entry_value, TR2_entry_value-TR);
}
}
/* top level */
/* assumes that GC_DOES_COPY. Should also work if everything is above */
/* the topmost choice point, though slower than the special purpose */
/* fast_copy garbage collector */
void fast_copy()
{
init_stats();
store_regs_in_env();
setup_cps_fast_copy();
fast_copy_gc_init();
init_marking_table();
fast_copy_trail();
fast_copy_control();
fast_copy_restore_top_env();
restore_cps_fast_copy();
fast_copy_stats();
compute_stats();
}
#endif